/** 
* @file        demo_ctwing.c
* @ingroup     cloud
* @brief       使用API实现与网络云平台ctwing交互的参考代码
* @attention  
* @note         
*/
#include "zos_config.h"

#ifdef BOARD_USING_CTIOT_DEMO
#include "zos.h"

/**
 * @brief 任务重试间隔时间
 */	
#define  WAIT_AGAIN_TIME              (5*1000)
/**
 * @brief 任务重试次数上限
 */	
#define  DO_AGAIN_TIMES               3

/**
 * @brief 简化demo的任务句柄
 */	
zos_task_t  ctiot_task_handle =NULL;
zos_mq_t ctiot_event_mq = ZOS_NULL;

zos_uint8_t buf[100]="hello ZusOS";
char *str = ZOS_NULL;

zos_uint8_t state=0;


typedef struct ctiot_event_msg{
    int     id;        ///< event id
    int     result;   ///< data type
}ctiot_event_msg_t;

typedef enum
{
    CTIOT_NOT_SENT = 0,
    CTIOT_SENT_WAIT_RESPONSE,
    CTIOT_SENT_FAIL,
    CTIOT_SENT_TIME_OUT,
    CTIOT_SENT_SUCCESS,
    CTIOT_SENT_GET_RST,
    CTIOT_SEND_PENDING,
} ctiot_send_status_e;

/*下行数据的回调函数，平台下发的数据都会在此处理；
严禁用户在此回调函数中阻塞或耗时较长的处理数据，应当在获取到数据后在另一线程处理*/
void  ctiot_downstream_hook(char *data, int data_len)
{
	(void) data_len;
    str=zos_zalloc(512);
    memset(str,0,512);
    strncpy(str,data,data_len);
    zos_printf("data=%s",str);
    zos_free(str);
}

/**
 *@brief notify到平台时ACK判断回调函数
 *@note 与ctiot_notify函数配合使用
 *@warning 
 */	
void ctiot_send_asyn_ack(int mid, int result)
{
    ctiot_event_msg_t *msg = ZOS_NULL;
    msg = zos_zalloc(sizeof(ctiot_event_msg_t));
    msg->id = mid;
    msg->result = result;
	zos_mq_send(ctiot_event_mq, &msg, 0, ZOS_WAITING_FOREVER);
}





/**
 *@brief 带ACK判断的notify接口
 *@note 内部实现了上报数据到平台，并且根据返回的ACK判断是否上传成功
 *@warning 
 */	
zos_err_t ctiot_notify(char *data, int len, int msg_type)
{
    int state = 0;
    if(cdp_send_syn(data,len,msg_type) == ZOS_ERROR)
    {
        return ZOS_ERROR;
    }
    ctiot_event_msg_t *msg = ZOS_NULL;
    msg = zos_zalloc(sizeof(ctiot_event_msg_t));
    state = zos_mq_recv(ctiot_event_mq,&msg,0,10*1000);
    if(state == ZOS_EOK)
    {
        if( msg->result == CTIOT_SENT_SUCCESS)
            return ZOS_EOK;
    }
    return ZOS_ERROR;
}



//rtc唤醒回调函数
void rtc_ctiot_callback(void *para)
{
    //RTC唤醒以后将state设置为5，用来提示RTC唤醒
    state = 5;
}

/**
 *@brief 简化demo的任务处理流程
 *@note 简化demo内部实现了简单的云平台的注册和发送上行数据流程
 *@warning 简化demo并未执行去注册操作，同时接收下行数据时用户必须实现回调接口ctiot_downstream_hook
 */	
void ctiot_task(void *args)
{
    zos_uint8_t i=30,cgact;
    int again_num = 0;
    (void) args;
    if(state == 5)
    {
        zos_printf("wakeup by rtc\r\n");
    }
    //判断是否从深睡眠醒来，如果启动来自深睡眠，则不会执行注册到cdp流程
    if(nb_get_powenon_from_deepsleep() ==ZOS_ERROR)
	{
        zos_printf("cdp opencpu demo start");
        //设置云平台的IP和PORT，云平台的IP和PORT会存储到NV中
        //CTWing:221.229.214.202;CDP:49.4.85.232
        if(cdp_cloud_setting("221.229.214.202", 5683) != ZOS_EOK)
        {
            zos_task_delay(5000);
            if(cdp_cloud_setting("221.229.214.202", 5683) != ZOS_EOK)
            {
                //注册到平台失败，将会重启模组。
                zos_printf("ctiot set ip failed\r\n");
                zos_reboot();
            }
        }

        //执行云平台注册流程
        while(cdp_register(86400, 30)  != ZOS_EOK)
        { 
            again_num++;
            if(again_num > DO_AGAIN_TIMES)
            {
                //链接平台超时，将会重启模组。
                zos_printf("register fail!!!");
                zos_reboot();
            }
            zos_task_delay(WAIT_AGAIN_TIME);
        }
        again_num = 0;
        zos_printf("register success!!!\r\n");
	}
    
    //注册成功后，发送上行数据
retry_send:
    if(ctiot_notify(buf, strlen(buf), 0) != ZOS_EOK)
    {
        again_num++;
        zos_printf("cdp_senddata fail!!!");
        if(again_num > DO_AGAIN_TIMES)
        {
            
            zos_printf("cdp_senddata fail!!!");
            goto task_exit;
        }
        zos_task_delay(3000);
        goto retry_send;
    }
    zos_printf("cdp_senddata ok!!!");

    //设置每天12点0分0秒-13点0分0秒，随机醒来
    //zos_rtc_set_by_day(ZOS_RTC_TIMER_ID_1,rtc_ctiot_callback,ZOS_NULL,12,1*60*60,0,0);
    zos_rtc_timer_create(ZOS_RTC_TIMER_ID_1,60,rtc_ctiot_callback,ZOS_NULL);

   
    // //在这里可以选择手动发送RAI，也可以使用带RAI的命令上报数据  cdp_send_asyn_with_rai(buf, strlen(buf),1);
    nb_send_rai();

    //  //进入休眠
    nb_work_unlock();
    zos_task_delay(30000);
    
task_exit:
    ctiot_task_handle = ZOS_NULL;
	zos_task_exit();
}


void ctiot_init(void)
{
    //注册下行数据的回调函数
    cdp_callbak_set(ctiot_downstream_hook, ctiot_send_asyn_ack);
    if(ctiot_event_mq == ZOS_NULL)
    {
        ctiot_event_mq = zos_mq_create(50,sizeof(void *));
    }
    //创建CDP的demo线程
	ctiot_task_handle = zos_task_create ("ctiot_task",ctiot_task,ZOS_NULL,0x400,task_Priority_Normal);

}

int demo_ctiot_init(int argc, char *argv[])
{
    ctiot_init();
    return ZOS_EOK;
}
#include "shell.h"

SHELL_EXPORT_CMD(demo_ctiot,demo_ctiot_init, ctiot demo);


int demo_ctiot_send(int argc, char *argv[])
{
   return   ctiot_notify("helo QS-100", strlen("helo QS-100"), 0);
}

SHELL_EXPORT_CMD(ctiot_send,demo_ctiot_send, ctiot send);

#endif


